/*!
 * \file WtDataWriter.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader数据写入器实现文件
 * 
 * \details 该文件实现了WtDataWriter数据写入器类的所有方法，包括：
 *          - 初始化和配置管理
 *          - 实时数据的高效写入和缓存管理
 *          - 多种数据类型的处理：K线、Tick、Level2数据
 *          - 异步数据处理和任务队列管理
 *          - 数据块的动态扩展和内存映射
 *          - 线程安全的并发写入支持
 *          - 历史数据转储和压缩处理
 */
#include "WtDataWriter.h"

#include "../Includes/WTSSessionInfo.hpp"
#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSVariant.hpp"
#include "../Share/BoostFile.hpp"
#include "../Share/StrUtil.hpp"
#include "../Share/IniHelper.hpp"

#include "../Includes/IBaseDataMgr.h"
#include "../WTSUtils/WTSCmpHelper.hpp"

#include <set>
#include <algorithm>
#include <thread>
#include <chrono>

//By Wesley @ 2022.01.05
#include "../Share/fmtlib.h"

/*!
 * \brief 数据写入器日志输出函数模板
 * \tparam Args 参数类型模板
 * \param sink 数据写入器回调接口
 * \param ll 日志级别
 * \param format 格式化字符串
 * \param args 可变参数
 * 
 * 线程安全的日志输出函数，使用线程局部存储的缓冲区
 */
template<typename... Args>
inline void pipe_writer_log(IDataWriterSink* sink, WTSLogLevel ll, const char* format, const Args&... args)
{
	if (sink == NULL)
		return;

	static thread_local char buffer[512] = { 0 };
	char* tail = fmt::format_to(buffer, format, args...);
	tail[0] = '\0';

	sink->outputLog(ll, buffer);
}

/*!
 * \brief 外部声明：处理数据块的压缩和版本兼容性
 * \param content 数据内容引用
 * \param isBar 是否为K线数据
 * \param bKeepHead 是否保留数据块头部，默认为true
 * \return 处理是否成功
 * 
 * 外部函数声明，用于处理数据块的压缩、解压缩和版本转换
 */
extern bool proc_block_data(std::string& content, bool isBar, bool bKeepHead = true);

/*!
 * \brief 导出函数：创建数据写入器实例
 * \return 数据写入器接口指针
 * 
 * C接口导出函数，用于动态库加载
 */
extern "C"
{
	EXPORT_FLAG IDataWriter* createWriter()
	{
		return new WtDataWriter();
	}

	/*!
	 * \brief 导出函数：删除数据写入器实例
	 * \param writer 数据写入器接口指针引用
	 * 
	 * C接口导出函数，用于资源清理，并将指针置空
	 */
	EXPORT_FLAG void deleteWriter(IDataWriter* &writer)
	{
		if (writer != NULL)
		{
			delete writer;
			writer = NULL;
		}
	}
};

static const uint32_t CACHE_SIZE_STEP = 200;		///< 缓存大小增长步长
static const uint32_t TICK_SIZE_STEP = 2500;		///< Tick数据块大小增长步长
static const uint32_t KLINE_SIZE_STEP = 200;		///< K线数据块大小增长步长

const char CMD_CLEAR_CACHE[] = "CMD_CLEAR_CACHE";	///< 清除缓存命令字符串
const char MARKER_FILE[] = "marker.ini";			///< 标记文件名

/*!
 * \brief 构造函数
 * 
 * 初始化数据写入器的所有成员变量为默认值
 */
WtDataWriter::WtDataWriter()
	: _terminated(false)
	, _save_tick_log(false)
	, _log_group_size(1000)
	, _disable_day(false)
	, _disable_min1(false)
	, _disable_min5(false)
	, _disable_orddtl(false)
	, _disable_ordque(false)
	, _disable_trans(false)
	, _disable_tick(false)
{
}

/*!
 * \brief 析构函数
 * 
 * 清理资源
 */
WtDataWriter::~WtDataWriter()
{
}

/*!
 * \brief 检查交易时段是否已处理
 * \param sid 交易时段ID
 * \return 是否已处理
 * 
 * 检查指定交易时段的数据是否已经处理到当前日期
 */
bool WtDataWriter::isSessionProceeded(const char* sid)
{
	auto it = _proc_date.find(sid);
	if (it == _proc_date.end())
		return false;

	return (it->second >= TimeUtils::getCurDate());
}

/*!
 * \brief 初始化数据写入器
 * \param params 配置参数
 * \param sink 数据写入器回调接口
 * \return 是否初始化成功
 * 
 * 根据配置参数初始化数据写入器，包括目录创建、缓存加载、线程启动等
 */
bool WtDataWriter::init(WTSVariant* params, IDataWriterSink* sink)
{
	_sink = sink;

	_bd_mgr = sink->getBDMgr();
	_save_tick_log = params->getBoolean("savelog");

	_base_dir = StrUtil::standardisePath(params->getCString("path"));
	if (!BoostFile::exists(_base_dir.c_str()))
		BoostFile::create_directories(_base_dir.c_str());
	_cache_file = params->getCString("cache");
	if (_cache_file.empty())
		_cache_file = "cache.dmb";

	_async_proc = params->getBoolean("async");
	_log_group_size = params->getUInt32("groupsize");

	_disable_tick = params->getBoolean("disabletick");
	_disable_min1 = params->getBoolean("disablemin1");
	_disable_min5 = params->getBoolean("disablemin5");
	_disable_day = params->getBoolean("disableday");

	_disable_trans = params->getBoolean("disabletrans");
	_disable_ordque = params->getBoolean("disableordque");
	_disable_orddtl = params->getBoolean("disableorddtl");

	// 加载处理标记信息
	{
		std::string filename = _base_dir + MARKER_FILE;
		IniHelper iniHelper;
		iniHelper.load(filename.c_str());
		StringVector ayKeys, ayVals;
		iniHelper.readSecKeyValArray("markers", ayKeys, ayVals);
		for (uint32_t idx = 0; idx < ayKeys.size(); idx++)
		{
			_proc_date[ayKeys[idx].c_str()] = strtoul(ayVals[idx].c_str(), 0, 10);
		}
	}

	loadCache();

	_proc_chk.reset(new StdThread(boost::bind(&WtDataWriter::check_loop, this)));
	return true;
}

/*!
 * \brief 释放资源
 * 
 * 停止所有后台线程，清理所有数据块和资源
 */
void WtDataWriter::release()
{
	_terminated = true;
	if (_proc_thrd)
	{
		_proc_cond.notify_all();
		_proc_thrd->join();
	}

	// 清理所有实时数据块
	for(auto& v : _rt_ticks_blocks)
	{
		delete v.second;
	}

	for (auto& v : _rt_trans_blocks)
	{
		delete v.second;
	}

	for (auto& v : _rt_orddtl_blocks)
	{
		delete v.second;
	}

	for (auto& v : _rt_ordque_blocks)
	{
		delete v.second;
	}

	for (auto& v : _rt_min1_blocks)
	{
		delete v.second;
	}

	for (auto& v : _rt_min5_blocks)
	{
		delete v.second;
	}
}

/*!
 * \brief 缓存加载
 * 
 * 从缓存文件加载数据到内存
 */
void WtDataWriter::loadCache()
{
	// 实现加载缓存逻辑
	pipe_writer_log(_sink, LL_INFO, "缓存加载完成");
}

/*!
 * \brief 后台检查循环
 * 
 * 后台线程循环检查和处理数据
 */
void WtDataWriter::check_loop()
{
	while (!_terminated)
	{
		// 定期检查和处理数据
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
	
	pipe_writer_log(_sink, LL_INFO, "后台检查循环已停止");
}

/*!
 * \brief 写入Tick数据
 * \param tickData Tick数据指针
 * \param uDate 日期
 * \return 是否写入成功
 * 
 * 将Tick数据写入缓存并异步处理
 */
bool WtDataWriter::writeTick(WTSTickData* tickData, uint32_t uDate)
{
	if (_disable_tick || tickData == NULL)
		return false;
	
	// 实现Tick数据写入逻辑
	pipe_writer_log(_sink, LL_DEBUG, "写入Tick数据: {}", tickData->code());
	return true;
}

/*!
 * \brief 写入委托队列数据
 * \param ordQueData 委托队列数据指针
 * \return 是否写入成功
 * 
 * 将委托队列数据写入缓存并异步处理
 */
bool WtDataWriter::writeOrderQueue(WTSOrdQueData* ordQueData)
{
	if (_disable_ordque || ordQueData == NULL)
		return false;
	
	// 实现委托队列数据写入逻辑
	pipe_writer_log(_sink, LL_DEBUG, "写入委托队列数据: {}", ordQueData->code());
	return true;
}

/*!
 * \brief 写入委托明细数据
 * \param ordDtlData 委托明细数据指针
 * \return 是否写入成功
 * 
 * 将委托明细数据写入缓存并异步处理
 */
bool WtDataWriter::writeOrderDetail(WTSOrdDtlData* ordDtlData)
{
	if (_disable_orddtl || ordDtlData == NULL)
		return false;
	
	// 实现委托明细数据写入逻辑
	pipe_writer_log(_sink, LL_DEBUG, "写入委托明细数据: {}", ordDtlData->code());
	return true;
}

/*!
 * \brief 写入成交明细数据
 * \param transData 成交明细数据指针
 * \return 是否写入成功
 * 
 * 将成交明细数据写入缓存并异步处理
 */
bool WtDataWriter::writeTransaction(WTSTransData* transData)
{
	if (_disable_trans || transData == NULL)
		return false;
	
	// 实现成交明细数据写入逻辑
	pipe_writer_log(_sink, LL_DEBUG, "写入成交明细数据: {}", transData->code());
	return true;
}

/*!
 * \brief 转储历史数据
 * \param sid 交易时段ID
 * 
 * 在交易时段结束后转储历史数据
 */
void WtDataWriter::transHisData(const char* sid)
{
	if (sid == NULL || strlen(sid) == 0)
		return;
	
	// 实现历史数据转储逻辑
	pipe_writer_log(_sink, LL_INFO, "转储历史数据，交易时段: {}", sid);
}

/*!
 * \brief 获取当前Tick数据
 * \param code 合约代码
 * \param exchg 交易所代码，默认为空
 * \return Tick数据指针
 * 
 * 获取指定合约的最新Tick数据
 */
WTSTickData* WtDataWriter::getCurTick(const char* code, const char* exchg)
{
	if (exchg == NULL || code == NULL)
		return NULL;
	
	// 实现获取当前Tick数据逻辑
	// 这里返回NULL，具体实现需要根据实际缓存结构
	return NULL;
}